package com.pearstack.sonic.core;

import com.pearstack.sonic.core.protocol.Protocol;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Objects;

/**
 * Sonic Socket 客户端
 *
 * @author 就眠儀式
 * */
public class SonicClient {

    private int port;

    private String host;

    private static final int BUFFER_SIZE = 1024;

    private AsynchronousSocketChannel socketChannel;

    private Protocol protocol;

    private SonicHandler handler;

    public SonicClient(String host, int port, SonicHandler handler) {
        this.host = host;
        this.port = port;
        this.handler = handler;
    }

    public SonicClient(String host, int port, Protocol protocol, SonicHandler handler) {
        this.host = host;
        this.port = port;
        this.protocol = protocol;
        this.handler = handler;
    }

    public void start() {
        try {
            socketChannel = AsynchronousSocketChannel.open();
            socketChannel.connect(new InetSocketAddress(host, port), null, new CompletionHandler<Void, Object>() {

                @Override
                public void completed(Void result, Object attachment) {

                    SonicSession session = new SonicSession(socketChannel);

                    handler.sessionCreated(session);

                    ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE);

                    socketChannel.read(byteBuffer, byteBuffer, new CompletionHandler<Integer, ByteBuffer>() {

                        @Override
                        public void completed(Integer result, ByteBuffer attachment) {

                            byteBuffer.flip();

                            handler.messageReceive(session, Objects.isNull(protocol) ? byteBuffer : protocol.encode(byteBuffer));

                            byteBuffer.clear();

                            socketChannel.read(byteBuffer, byteBuffer, this);
                        }

                        @Override
                        public void failed(Throwable exc, ByteBuffer attachment) {

                            handler.exceptionCaught(session, exc);
                        }
                    });
                }

                @Override
                public void failed(Throwable exc, Object attachment) {

                    handler.exceptionCaught(null, exc);
                }
            });

        } catch (IOException e) {

            e.printStackTrace();
        }
    }

    public void close() {

    }
}
